//API请求签名工具类
//@author superman
//@verson1.0

//签名生成的通用步骤如下：
//第一步，设所有发送或者接收到的数据为集合M，将集合M内非空参数值的参数按照参数名ASCII码从小到大排序（字典序），使用URL键值对的格式（即key1=value1&key2=value2…）拼接成字符串stringA。

//特别注意以下重要规则：
//◆ 参数名ASCII码从小到大排序（字典序）；
//◆ 如果参数的值为空不参与签名；
//◆ 参数名区分大小写；
//◆ 需要请求参数是Bean结构数据时，bean结点仍以JSON串组装，且整个json串做为value参与签名

//第二步，在stringA最后拼接上secret得到stringSignTemp字符串，并对stringSignTemp进行MD5或SHA1运算，再将得到的字符串所有字符转换为大写，得到sign值signValue

//必要参数
//以下必要字段参与签名，每个交易都需要添加，不在交易接口描述中再做说明
//
//OAUTH_APPID	应用实例名
//OAUTH_METHOD	签名方法，目前支持MD5，SHA1,后续会兼容、SHA256、HMAC
//OAUTH_TIMESTAMP	时间截，以后误差不超过5分钟
//OAUTH_NONCE	随机数，建议使用纳秒数做为随机数
//OAUTH_OPENID	非必填项，如登陆后则采用SESSIONID作为OPENID

//说明:其中secret为固定的一个字符串拼接上当前月份的英文,md5后专成大写字符串,并截取前16位,不足16位补足F

//配置签名参数
//var SALT = 'yAqPxwSTwLTwahTZWsdEmZJS'
// 配置是否启用签名
var SIGN = true
// ////////////////////以上是是否开启签名的配置////////////////////////////////////

//八维通平台
//var appid = 'c81e728d9d4c2f636f067f89cc14862c'
var secretid = 'pZTo79iBIUz7XTYshEUxoNfTmPMroy'
/**
 * 签名函数.将JSON格式的请求字符串按预定的签名方式签名,并返回签名后可直接用于API传输的请求报文
 *
 * @param {Object}
 *            obj JSON格式的请求字符串 token API放问token sessionid
 *            登录的话就传入sessionid.没有的话就传空
 */
function signinopen(obj, sessionid) {
  //sessionid = "";
  // secretid = secret != undefined && secret != null ? secret : '';
  if (SIGN) {
    // 转换成JSON对象
    // console.log("原始json串:" + obj)
    // console.log("--------------------------------------")

    var jsonObj = JSON.parse(obj)

    // 根据签名规则置入签名参数
    jsonObj = generateSignObj(jsonObj, sessionid)
    // console.log(jsonObj)
    // console.log("--------------------------------------")

    // 临时数组,用于存放JSON对象的key
    var tmpArr = []

    for (var key in jsonObj) {
      // 值非空
      // if (jsonObj[key] != undefined && jsonObj[key] != null)
      tmpArr[tmpArr.length] = key
    }

    // 字典排序
    tmpArr.sort()

    var result = ''

    // 遍历 并且拼接待签名的字符串
    for (var i in tmpArr) {
      var key = tmpArr[i]
      var value = jsonObj[key]

      if (jsonObj[key] == undefined || jsonObj[key] == null) value = ''

      // console.log(value)

      // console.log("urlbefore:" + (value.toString()));
      // 为了配合待签名的字符串中value不带引号,故判断value是否是JSON对象
      value = encodeURIComponent(isJson(value) ? JSON.stringify(value) : value)

      // console.log("urlafter:" + value)
      // console.log("--------------------------------------")
      value = value.replace(/\!/g, '%21')
      value = value.replace(/\'/g, '%27')
      value = value.replace(/\(/g, '%28')
      value = value.replace(/\)/g, '%29')
      value = value.replace(/\*/g, '%2A')

      var rs = key + '=' + value
      result += rs
      if (i < tmpArr.length - 1) result += '&'
    }

    // 直接拼接用于签名的secret
    result += secretid;

     console.log("代签名:" + result)

    // 将待签名的字符串做MD5签名,并转换成大写

    result = md5(result).toLocaleUpperCase()

    // 将签名结果置入JSON对象中
    jsonObj['SIGN'] = result

    jsonObj = removeKeyFromResult(jsonObj)

    return JSON.stringify(jsonObj)
  } else {
    return obj
  }
}

/**
 * 移除不参与签名的参数
 */
function removeKeyFromResult(jsonObj) {
  if (secretid === '') delete jsonObj['OAUTH_APPID']
  delete jsonObj['OAUTH_OPENID']
  return jsonObj
}

/**
 * 置入待签名参数
 *
 * @param {Object}
 *            jsonObj
 */
function generateSignObj(jsonObj, sessionid) {
  jsonObj['OAUTH_APPID'] = appid
  jsonObj['OAUTH_METHOD'] = 'MD5'
  jsonObj['OAUTH_TIMESTAMP'] = Date.parse(new Date()) / 1000
  jsonObj['OAUTH_NONCE'] = generateUUID()
  if (
    sessionid != undefined &&
    sessionid != null &&
    sessionid != 'null' &&
    sessionid != ''
  )
    jsonObj['OAUTH_OPENID'] = sessionid
  return jsonObj
}

/**
 * 生成UUID唯一字符窜
 */
function generateUUID() {
	var s = [];
	var hexDigits = "0123456789abcdef";
	for (var i = 0; i < 36; i++) {
		s[i] = hexDigits.substr(Math.floor(Math.random() * 0x10), 1);
	}
	s[14] = "4"; // bits 12-15 of the time_hi_and_version field to 0010
	s[19] = hexDigits.substr((s[19] & 0x3) | 0x8, 1); // bits 6-7 of the
	// clock_seq_hi_and_reserved
	// to 01
	s[8] = s[13] = s[18] = s[23] = "-";

	var uuid = s.join("");
	return uuid;
}

/**
 * 判断传入的对象是否是JSON对象
 * 
 * @param {Object}
 *            obj
 */
function isJson(obj) {
	var isjson = typeof (obj) == "object"
			&& Object.prototype.toString.call(obj).toLowerCase() == "[object object]"
			&& !obj.length;
	var isArray = obj && typeof obj === 'object' && Array == obj.constructor;
	return isjson || isArray;
}



